{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 1. 函数的创建和调用及参数传递"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "30\n",
      "30\n"
     ]
    }
   ],
   "source": [
    "def calc(a, b):  # a,b为形式参数，形参，形参的位置是在函数的定义处\n",
    "    c = a + b\n",
    "    return c\n",
    "\n",
    "result = calc(10, 20)  # 10,20是实际参数，实参，位置是在函数调用处\n",
    "print(result)\n",
    "\n",
    "res = calc(b=10, a=20)  # 标记了的参数，有变量名，等号左侧变量的名称称为关键字参数\n",
    "print(res)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 2. 函数参数传递的内存分析"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "n1= 11\n",
      "n2= [22, 33, 44]\n",
      "arg1= 11\n",
      "arg2= [22, 33, 44]\n",
      "arg1= 100\n",
      "arg2= [22, 33, 44, 10]\n",
      "n1= 11\n",
      "n2= [22, 33, 44, 10]\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "'\\n在函数调用过程中，进行参数的传递\\n如果是不可变对象，在函数体的修改不会影响实参的值   arg1修改为100，不会影响n1的值\\n如果是可变对象，在函数体内的修改会影响实参的值   arg2的修改，增加10，会影响n2的值，列表是可变对象\\n'"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 形参和实参名字可以不痛\n",
    "def fun(arg1, arg2):\n",
    "    print('arg1=', arg1)\n",
    "    print('arg2=', arg2)\n",
    "    arg1 = 100\n",
    "    arg2.append(10)\n",
    "    print('arg1=', arg1)\n",
    "    print('arg2=', arg2)\n",
    "    # return\n",
    "\n",
    "\n",
    "n1 = 11\n",
    "n2 = [22, 33, 44]\n",
    "print('n1=', n1)\n",
    "print('n2=', n2)\n",
    "fun(n1, n2)  # 位置传参，arg为形参，n为实参，实参形参可以不同\n",
    "print('n1=', n1)\n",
    "print('n2=', n2)\n",
    "\n",
    "\"\"\"\n",
    "在函数调用过程中，进行参数的传递\n",
    "如果是不可变对象，在函数体的修改不会影响实参的值   arg1修改为100，不会影响n1的值\n",
    "如果是可变对象，在函数体内的修改会影响实参的值   arg2的修改，增加10，会影响n2的值，列表是可变对象\n",
    "\"\"\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 3. 函数返回值"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "([29, 23, 53, 55], [10, 34, 44])\n",
      "hello\n",
      "hello\n",
      "('hello', 'world')\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "'\\n函数在定义时是否需要返回值，视情况而定\\n'"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 函数返回多个值时，结果是元组\n",
    "def fun(num):\n",
    "    odd = []  # 存奇数\n",
    "    even = []  # 存偶数\n",
    "    for i in num:\n",
    "        if i % 2:\n",
    "            odd.append(i)\n",
    "        else:\n",
    "            even.append(i)\n",
    "    return odd, even\n",
    "\n",
    "\n",
    "# 函数的调用\n",
    "print(fun([10, 29, 34, 23, 44, 53, 55]))\n",
    "\n",
    "\"\"\"\n",
    "函数的返回值：\n",
    "1.如果函数没有返回值（函数执行完毕之后，不需要给调用处提供数据），return可以不写\n",
    "2.函数的返回值，如果是1个，直接返回原类型\n",
    "3.函数的返回值，如果是多个，返回结果是元组\n",
    "\"\"\"\n",
    "\n",
    "\n",
    "def fun1():\n",
    "    print('hello')\n",
    "\n",
    "\n",
    "fun1()\n",
    "\n",
    "\n",
    "def fun2():\n",
    "    return 'hello'\n",
    "\n",
    "\n",
    "res = fun2()\n",
    "print(res)\n",
    "\n",
    "\n",
    "def fun3():\n",
    "    return 'hello', 'world'\n",
    "\n",
    "\n",
    "print(fun3())\n",
    "\n",
    "\"\"\"\n",
    "函数在定义时是否需要返回值，视情况而定\n",
    "\"\"\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 4. 函数的参数定义"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "100 10\n",
      "20 30\n",
      "hello\thello\n",
      "(10,)\n",
      "(10, 20, 30)\n",
      "{'a': 10}\n",
      "{'a': 10, 'b': 20, 'c': 30}\n",
      "hello world java\n"
     ]
    }
   ],
   "source": [
    "# 默认值参数\n",
    "def fun1(a, b=10):  # b为默认值参数\n",
    "    print(a, b)\n",
    "\n",
    "\n",
    "fun1(100)  # 100给a，b用默认值\n",
    "fun1(20, 30)  # 30将替换默认值10\n",
    "\n",
    "print('hello', end='\\t')  # 默认end是换行\n",
    "print('hello')\n",
    "\n",
    "\n",
    "# 个数可变的位置参数，只能定义一个*\n",
    "def fun2(*args):  # *表示参数个数可变\n",
    "    print(args)\n",
    "\n",
    "\n",
    "fun2(10)\n",
    "fun2(10, 20, 30)\n",
    "\n",
    "\n",
    "# 个数可变的关键字形参，只能定义一个**\n",
    "def fun3(**args):  # **表示关键字形参，不知道个数多少\n",
    "    print(args)\n",
    "\n",
    "\n",
    "fun3(a=10)\n",
    "fun3(a=10, b=20, c=30)  # 结果为字典\n",
    "\n",
    "\n",
    "print('hello', 'world', 'java')  # eg\n",
    "\n",
    "\n",
    "# *和**可以各有一个，*必须在**之前"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 5. 函数的参数总结"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "a= 10\n",
      "b= 20\n",
      "c= 30\n",
      "a= 11\n",
      "b= 22\n",
      "c= 33\n",
      "a= 100\n",
      "b= 200\n",
      "c= 300\n",
      "a= 111\n",
      "b= 222\n",
      "c= 333\n",
      "(10, 20, 30)\n",
      "{'a': 11, 'b': 22, 'c': 33, 'd': 44}\n",
      "a= 10\n",
      "b= 20\n",
      "c= 30\n",
      "d= 40\n",
      "a= 10\n",
      "b= 20\n",
      "c= 30\n",
      "d= 40\n",
      "a= 10\n",
      "b= 20\n",
      "c= 30\n",
      "d= 40\n",
      "a= 10\n",
      "b= 20\n",
      "c= 30\n",
      "d= 40\n",
      "a= 10\n",
      "b= 20\n",
      "c= 30\n",
      "d= 40\n"
     ]
    }
   ],
   "source": [
    "def fun(a, b, c):  # abc在函数定义处，是形式参数\n",
    "    print('a=', a)\n",
    "    print('b=', b)\n",
    "    print('c=', c)\n",
    "\n",
    "\n",
    "# 函数的调用\n",
    "fun(10, 20, 30)  # 函数调用时的参数传递，称为位置传参\n",
    "lst = [11, 22, 33]\n",
    "fun(*lst)  # 在函数调用时，将列表中的每个元素都转换为位置实参传入\n",
    "\n",
    "fun(a=100, c=300, b=200)  # 函数的调用，关键字实参\n",
    "dic = {'a': 111, 'b': 222, 'c': 333}\n",
    "fun(**dic)  # 在函数调用时，将字典中的键值对都转换为关键字实参传入\n",
    "\n",
    "\n",
    "def fun1(a, b=10):  # b是在函数的定义处，所以b是形参，而且进行了赋值，所以b称为默认值形参\n",
    "    print('a=', a)\n",
    "    print('b=', b)\n",
    "\n",
    "\n",
    "def fun2(*args):  # 个数可变的位置形参\n",
    "    print(args)\n",
    "\n",
    "\n",
    "def fun3(**args):  # 个数可变的关键字形参\n",
    "    print(args)\n",
    "\n",
    "\n",
    "fun2(10, 20, 30)\n",
    "fun3(a=11, b=22, c=33, d=44)\n",
    "\n",
    "\n",
    "def fun4(a, b, c, d):\n",
    "    print('a=', a)\n",
    "    print('b=', b)\n",
    "    print('c=', c)\n",
    "    print('d=', d)\n",
    "\n",
    "\n",
    "fun4(10, 20, 30, 40)  # 位置实参传递\n",
    "fun4(a=10, b=20, c=30, d=40)  # 关键字实参传递\n",
    "fun4(10, 20, c=30, d=40)  # 前两个参数使用位置实参传递，后两个参数使用关键字实参传递\n",
    "\n",
    "\n",
    "# 需求，cd只能用关键字实参传递\n",
    "# 从*之后的参数，在函数调用时，只能采用关键字参数传递\n",
    "def fun5(a, b, *, c, d):\n",
    "    print('a=', a)\n",
    "    print('b=', b)\n",
    "    print('c=', c)\n",
    "    print('d=', d)\n",
    "\n",
    "\n",
    "fun5(a=10, b=20, c=30, d=40)\n",
    "fun5(10, 20, c=30, d=40)\n",
    "\n",
    "\"\"\"\n",
    "函数定义时的形参的顺序问题\n",
    "\"\"\"\n",
    "\n",
    "\n",
    "def fun6(a, b, *, c, d, **args):\n",
    "    pass\n",
    "\n",
    "\n",
    "def fun7(*args, **kwargs):\n",
    "    pass\n",
    "\n",
    "\n",
    "def fun8(a, b=10, *args, **kwargs):\n",
    "    pass"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 6. 变量的作用域"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "杨老师\n",
      "杨老师\n",
      "20\n",
      "20\n"
     ]
    }
   ],
   "source": [
    "def fun(a, b):\n",
    "    c = a * b  # c为局部变量，因为c在函数体内进行定义的变量，ab为函数的形参，作用范围也是函数内部，相当于局部变量\n",
    "    print(c)\n",
    "\n",
    "\n",
    "# print(a, c)  # 因为a和c超出了起作用的范围（超出了作用域）\n",
    "\n",
    "\n",
    "name = '杨老师'\n",
    "print(name)\n",
    "\n",
    "\n",
    "def fun2():\n",
    "    print(name)\n",
    "\n",
    "\n",
    "fun2()  # name的作用范围为函数的内部和外部都可以使用，称为全局变量\n",
    "\n",
    "\n",
    "def fun3():\n",
    "    global age  # 函数内部定义的变量，局部变量，局部变量可以使用global进行生命，这个变量实际上就变成了全局变量\n",
    "    age = 20\n",
    "    print(age)\n",
    "\n",
    "\n",
    "fun3()\n",
    "print(age)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 7. 递归函数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "720\n"
     ]
    }
   ],
   "source": [
    "def fac(n):\n",
    "    if n == 1:\n",
    "        return 1\n",
    "    else:\n",
    "        res = n * fac(n-1)\n",
    "        return res\n",
    "\n",
    "\n",
    "print(fac(6))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 8. 斐波那契数列"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "8\n",
      "1\n",
      "1\n",
      "2\n",
      "3\n",
      "5\n",
      "8\n"
     ]
    }
   ],
   "source": [
    "def fib(n):\n",
    "    if n == 1:\n",
    "        return 1\n",
    "    elif n == 2:\n",
    "        return 1\n",
    "    else:\n",
    "        res = fib(n-1) + fib(n-2)\n",
    "        return res\n",
    "\n",
    "\n",
    "# 斐波那契数列第6位上的数字\n",
    "print(fib(6))\n",
    "\n",
    "\n",
    "# 输出这个数列前6位上的数字\n",
    "for i in range(1, 7):\n",
    "    print(fib(i))"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3.6.3",
   "language": "python",
   "name": "python3.6.3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.3"
  },
  "toc": {
   "base_numbering": 1,
   "nav_menu": {},
   "number_sections": false,
   "sideBar": true,
   "skip_h1_title": false,
   "title_cell": "Table of Contents",
   "title_sidebar": "Contents",
   "toc_cell": false,
   "toc_position": {
    "height": "calc(100% - 180px)",
    "left": "10px",
    "top": "150px",
    "width": "480px"
   },
   "toc_section_display": true,
   "toc_window_display": true
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
